/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package fr.insta.browser.view.webview;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.io.StringWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

/**
 * <p>JFXWebViewAdapter class.</p>
 *
 * @author Maarek
 * @version $Id: $Id
 */
public class JFXWebViewAdapter extends JPanel implements SwingWebView {

    final private JFXPanel jfxPanel = new JFXPanel();
    private WebEngine engine;
    final private JProgressBar progressBar = new JProgressBar();
    final private WebViewListenerCollection listeners = new WebViewListenerCollection();
    private int zoomLevel = 1;

    /**
     * Creates new form SwingWebview
     */
    public JFXWebViewAdapter() {
        super();
        initComponents();
        createScene();
    }

    private void initComponents() {
        setLayout(new BorderLayout());
        progressBar.setPreferredSize(new Dimension(150, 18));
        progressBar.setStringPainted(true);

        JPanel statusBar = new JPanel(new BorderLayout());
        statusBar.setBorder(BorderFactory.createEmptyBorder(3, 5, 3, 5));
        statusBar.add(progressBar, BorderLayout.EAST);

        add(jfxPanel, BorderLayout.CENTER);
        add(statusBar, BorderLayout.SOUTH);
        setPreferredSize(new Dimension(1024, 600));
    }

    private void createScene() {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {

                WebView view = new WebView();
                engine = view.getEngine();
                jfxPanel.setScene(new Scene(view));

                engine.getLoadWorker().workDoneProperty().addListener(new ChangeListener<Number>() {
                    @Override
                    public void changed(ObservableValue<? extends Number> observableValue, Number oldValue, final Number newValue) {
                        SwingUtilities.invokeLater(new Runnable() {
                            @Override
                            public void run() {
                                progressBar.setValue(newValue.intValue());
                            }
                        });
                    }
                });

                engine.titleProperty().addListener(new ChangeListener<String>() {
                    @Override
                    public void changed(ObservableValue<? extends String> observable, final String oldValue, final String newValue) {
                        SwingUtilities.invokeLater(new Runnable() {
                            @Override
                            public void run() {
                                listeners.onTitleChange(JFXWebViewAdapter.this, oldValue, newValue);
                            }
                        });
                    }
                });

                engine.locationProperty().addListener(new ChangeListener<String>() {
                    @Override
                    public void changed(ObservableValue<? extends String> observable, final String oldValue, final String newValue) {
                        SwingUtilities.invokeLater(new Runnable() {
                            @Override
                            public void run() {
                                listeners.onLocationChange(JFXWebViewAdapter.this, oldValue, newValue);
                            }
                        });
                    }
                });
            }
        });

    }

    /** {@inheritDoc} */
    @Override
    public void loadURL(final String url) {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                engine.load(fixUrl(url));
            }
        });
    }

    /** {@inheritDoc} */
    @Override
    public String getUrl() {
        return engine.getLocation();
    }

    /** {@inheritDoc} */
    @Override
    public String getPageTitle() {
        return engine.getTitle();
    }

    private static String fixUrl(String url) {
        if (!url.startsWith("http://") && !url.startsWith("https://")) {
            return "http://" + url;
        } else {
            return url;
        }
    }

    /** {@inheritDoc} */
    @Override
    public JPanel getPanel() {
        return this;
    }

    /** {@inheritDoc} */
    @Override
    public void executeJavaScript(final String js) {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                engine.executeScript(js);
            }
        });
    }

    /** {@inheritDoc} */
    @Override
    public void zoomIn() {
        zoomLevel++;
        executeJavaScript("(function() { "
                + " var body = document.getElementsByTagName('body')[0]; "
                + " body.style.fontSize = '" + (100 + zoomLevel * 10) + "%'; "
                + "})(); ");
    }

    /** {@inheritDoc} */
    @Override
    public void zoomOut() {
        zoomLevel--;
        executeJavaScript("(function() { "
                + " var body = document.getElementsByTagName('body')[0]; "
                + " body.style.fontSize = '" + (100 + zoomLevel * 10) + "%'; "
                + "})(); ");
    }

    /** {@inheritDoc} */
    public void addListener(WebViewListener listener) {
        listeners.addListener(listener);
    }

    /** {@inheritDoc} */
    @Override
    public void removeListener(WebViewListener listener) {
        listeners.removeListener(listener);
    }

    /** {@inheritDoc} */
    @Override
    public String getSource() {
        try {
            DOMSource domSource = new DOMSource(engine.getDocument());
            StringWriter writer = new StringWriter();
            StreamResult result = new StreamResult(writer);
            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            transformer.transform(domSource, result);
            return writer.toString();
        } catch (TransformerConfigurationException ex) {
            Logger.getLogger(JFXWebViewAdapter.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TransformerException ex) {
            Logger.getLogger(JFXWebViewAdapter.class.getName()).log(Level.SEVERE, null, ex);
        } 
       return null;
    }
}
